////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxncsservice.cpp
/// @brief CamX NCS Service class
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxncsservice.h"
#include "camxncsintfqsee.h"
#include "camxincs.h"
#include "camxosutils.h"

CAMX_NAMESPACE_BEGIN

/*
    初始化NCS线程的数据句柄，创建NCSIntfQSEE对象，若创建成功且传感器可用、能力可用，则将NCSIntfQSEE对象强转为接口类型并传递给NCSService的成员变量m_hNCSServiceContext，并将其初始化
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::Initialize
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::Initialize(
    ChiContext* pChiContext)
{
    // NCS的接口
    INCSIntfBase* pNCSIntfObject  = NULL;
    // NCS QSEE的实现类
    NCSIntfQSEE*  pNCSQSEEObject  = NULL;
    CamxResult    result          = CamxResultSuccess;

    if (NULL != pChiContext)
    {
        // NCS线程的数据句柄，用Chi上下文的线程管理者去管理NCS线程
        m_hNCSPollThHandle.pThreadManager = pChiContext->GetThreadManager();

        // Create and initialize the Sensor API interface object
        for (UINT i = 0; i < MaxSensorInterfaceObjects; i++ )
        {
            if (i == QSEE) // for now using only QSEE, add code for others
            {
                // 创建NCS QSEE对象
                result = NCSIntfQSEE::Create(&pNCSQSEEObject, pChiContext, this);

                // 如果返回成功值
                if (CamxResultSuccess == result)
                {
                    // 如果创建成功
                    if (NULL != pNCSQSEEObject)
                    {
                        // 将NCS QSEE对象强转为接口类型
                        pNCSIntfObject = static_cast<INCSIntfBase*>(pNCSQSEEObject);

                        // 验证NCS QSEE的最后一个传感器是否可用
                        result = pNCSIntfObject->GetListOfSensors();

                        if (CamxResultSuccess == result)
                        {
                            // 查询NCS QSEE是否支持最后一个传感器能力是否可用
                            result = pNCSIntfObject->QueryCapabilites();
                            if (CamxResultSuccess == result)
                            {
                                CAMX_LOG_INFO(CamxLogGroupNCS, "Probed a QSEE session");

                                // Save the interface object, it has the sensor list and its capabilities
                                // 初始化成员变量m_hNCSServiceContext
                                m_hNCSServiceContext.pNCSIntfObject[QSEE]  = pNCSIntfObject;
                                m_hNCSServiceContext.numActiveClients      = 0;
                                m_hNCSServiceContext.isSessionCreated      = FALSE;
                            }
                            else
                            {
                                CAMX_DELETE pNCSIntfObject;
                                pNCSIntfObject                            = NULL;
                                m_hNCSServiceContext.pNCSIntfObject[QSEE] = NULL;
                                CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to get capabilities !!");
                            }
                        }
                        else
                        {
                            CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to get list of sensors !!");
                        }
                    }
                    else
                    {
                        CAMX_LOG_ERROR(CamxLogGroupNCS, "Invalid interface object returned on create!!");
                        result = CamxResultEInvalidPointer;
                    }
                }
                else
                {
                    CAMX_LOG_ERROR(CamxLogGroupNCS, "NULL pNCSIntfObject %p", pNCSIntfObject);
                    result = CamxResultENoMemory;
                }
            }
            else
            {
                // all other interface types are unsupported
                m_hNCSServiceContext.pNCSIntfObject[i]        = NULL;
                result                                        = CamxResultSuccess;
            }
        }
    }
    else
    {
        m_hNCSPollThHandle.pThreadManager = NULL;
        result                            = CamxResultEInvalidArg;
        CAMX_LOG_ERROR(CamxLogGroupNCS, "Chi context pointer is null");
    }


    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::CreateClientSession
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::CreateClientSession(
    VOID* pSensor)
{
    INCSIntfBase*  pNCSIntfObject  = NULL;
    CamxResult     result          = CamxResultSuccess;

    CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Creating client session");

    pNCSIntfObject = m_hNCSServiceContext.pNCSIntfObject[QSEE];
    if (NULL != pNCSIntfObject)
    {
        result = pNCSIntfObject->CreateClientSession(pSensor);
        if (CamxResultSuccess == result)
        {
            m_hNCSServiceContext.isSessionCreated = TRUE;
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupNCS, "QSEE interface object is NULL");
        result = CamxResultEInvalidPointer;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::RegisterService
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
NCSSensor* NCSService::RegisterService(
    NCSSensorType sensorType,
    VOID*         pConfigParams)
{
    NCSSensor*    pSensorObject     = NULL;
    INCSIntfBase* pNCSIntfObject    = NULL;
    CamxResult    result            =  CamxResultSuccess;

    pNCSIntfObject = m_hNCSServiceContext.pNCSIntfObject[QSEE];

    if (NULL != pNCSIntfObject)
    {

        if (MaxSupportedSensorClients != pNCSIntfObject->GetNumActiveClients())
        {
            pSensorObject = static_cast<NCSSensor*>
                (pNCSIntfObject->RegisterService(sensorType, pConfigParams));

            // When succeeds, increment num of active clients in Service context.
            if (NULL != pSensorObject)
            {
                m_hNCSServiceContext.numActiveClients += 1;

                // Start the NCS service when the first time a client is registered.
                if (1 == pNCSIntfObject->GetNumActiveClients())
                {
                    result = StartNCSService();

                    // Failure to start thread, unregister the earlier registered sensor.
                    if (CamxResultSuccess != result)
                    {
                        result = pNCSIntfObject->UnregisterService(pSensorObject);
                        if (CamxResultSuccess != result)
                        {
                            CAMX_LOG_ERROR(CamxLogGroupNCS, "Client unregister cleanup failed !!");
                        }
                        pSensorObject = NULL;
                    }
                }
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to register to Sensor service object, returning NULL to client");
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupNCS, "Invalid QSEE interface handle");
    }

    return pSensorObject;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::UnregisterService
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::UnregisterService(
    NCSSensor* pSensorObject)
{
    CamxResult    result             = CamxResultSuccess;
    INCSIntfBase* pNCSIntfHandleQSEE = NULL;

    CAMX_LOG_INFO(CamxLogGroupNCS, "Unregister handle: %p", pSensorObject);

    pNCSIntfHandleQSEE = m_hNCSServiceContext.pNCSIntfObject[QSEE];

    if (0 == pNCSIntfHandleQSEE->GetNumActiveClients())
    {
        CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to unregister, no more clients exist");
        result = CamxResultENoMore;
    }
    else
    {
        result = pNCSIntfHandleQSEE->UnregisterService(pSensorObject);
        if (CamxResultSuccess == result)
        {
            if (0 == pNCSIntfHandleQSEE->GetNumActiveClients())
            {
                result = StopNCSService();
                if (CamxResultSuccess != result)
                {
                    CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to stop the NCS service");
                }
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to unregister");
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::QueryCapabilites
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::QueryCapabilites(
    NCSSensorCaps* pCaps,
    NCSSensorType  sensorType)
{
    CamxResult  result          = CamxResultSuccess;
    CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Client Querying capabilities");

    /// todo (CAMX-2393) remove hardcode of QSEE
    INCSIntfBase* pNCSIntfObject = m_hNCSServiceContext.pNCSIntfObject[QSEE];
    if (NULL != pNCSIntfObject)
    {
        result = pNCSIntfObject->FillCaps(pCaps, sensorType);
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupNCS, "Invalid QSEE interface handle");
        result = CamxResultEInvalidPointer;
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::ReleaseSession
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::ReleaseSession()
{
    CamxResult    result         = CamxResultSuccess;
    INCSIntfBase* pNCSIntfObject = NULL;

    CAMX_LOG_VERBOSE(CamxLogGroupNCS, "NCS Release session");

    // todo (CAMX-2393) remove hardcode when ANI interface is implemented
    pNCSIntfObject  = m_hNCSServiceContext.pNCSIntfObject[QSEE];
    if (pNCSIntfObject != NULL)
    {
        if (TRUE == m_hNCSServiceContext.isSessionCreated)
        {
            result                                = pNCSIntfObject->Release(NULL);
            m_hNCSServiceContext.isSessionCreated = FALSE;
        }
        else
        {
            CAMX_LOG_WARN(CamxLogGroupNCS, "Session not created but trying to release !!");
            result = CamxResultEInvalidState;
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupNCS, "Invalid QSEE interface handle");
        result = CamxResultEInvalidPointer;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::StartNCSService
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::StartNCSService()
{
    CamxResult     result             = CamxResultEFailed;
    NCSThreadData* pThreadData        = NULL;
    VOID*          pThreadInputs[1]   = { pThreadData };

    result = m_hNCSPollThHandle.pThreadManager->RegisterJobFamily(NCSService::NCSServicePollThread,
                                                                  "NonCameraSensors",
                                                                  NULL,
                                                                  JobPriority::High,
                                                                  FALSE,
                                                                  &m_hNCSPollThHandle.hJobHandle);

    CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Starting the NCS Service thread");

    if (CamxResultSuccess == result)
    {
        m_hNCSPollThHandle.pNCSQMutex       = Mutex::Create("NCSJobQMutex");
        m_hNCSPollThHandle.pNCSQCondVar     = Condition::Create("NCSJobQCondVar");
        m_hNCSPollThHandle.pNCSStateMutex   = Mutex::Create("NCSStateMutex");
        m_hNCSPollThHandle.pNCSStateCondVar = Condition::Create("NCSStateCondVar");
        m_hNCSPollThHandle.pServiceObject   = this;

        pThreadData = static_cast<NCSThreadData*>(CAMX_CALLOC(sizeof(NCSThreadData)));

        if (NULL != pThreadData)
        {
            pThreadData->pJob = NULL;
            pThreadData->pThreadContext = &m_hNCSPollThHandle;

            pThreadInputs[0] = pThreadData;
            m_hNCSPollThHandle.pThreadManager->PostJob(m_hNCSPollThHandle.hJobHandle,
                NULL,
                reinterpret_cast<VOID**>(&pThreadInputs),
                FALSE,
                FALSE);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupNCS, "Out of memory!!");
            result = CamxResultENoMemory;
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::StopNCSService
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::StopNCSService()
{
    CamxResult result = CamxResultSuccess;

    if (InvalidJobHandle != m_hNCSPollThHandle.hJobHandle)
    {

        result = FlushNCSService();
        if (CamxResultSuccess == result)
        {
            result = m_hNCSPollThHandle.pThreadManager->UnregisterJobFamily(NULL,
                                                                        "NonCameraSensors",
                                                                        m_hNCSPollThHandle.hJobHandle);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupNCS, "Flush failed !!");
        }

        m_hNCSPollThHandle.hJobHandle = InvalidJobHandle;
        m_hNCSPollThHandle.pNCSQMutex->Destroy();
        m_hNCSPollThHandle.pNCSQCondVar->Destroy();
        m_hNCSPollThHandle.pNCSStateMutex->Destroy();
        m_hNCSPollThHandle.pNCSStateCondVar->Destroy();

        m_hNCSPollThHandle.pNCSQMutex       = NULL;
        m_hNCSPollThHandle.pNCSQCondVar     = NULL;
        m_hNCSPollThHandle.pNCSStateMutex   = NULL;
        m_hNCSPollThHandle.pNCSStateCondVar = NULL;

    }

    CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Stopped the NCS Service thread");

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::FlushNCSService
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::FlushNCSService()
{
    CamxResult result = CamxResultSuccess;
    NCSJob*    pJob   = NULL;

    // Flush and wait for flush to be done.
    if (InvalidJobHandle != m_hNCSPollThHandle.hJobHandle)
    {
        pJob = static_cast<NCSJob*>(CAMX_CALLOC(sizeof(NCSJob)));

        if (NULL != pJob)
        {
            pJob->jobType = NCSFlushCmdType;
            pJob->pPayload = NULL;

            // Send flush and wait for flush to be done.
            result = EnqueueJob(pJob);
            if (CamxResultSuccess == result)
            {
                // Wait for flush to be done.
                m_hNCSPollThHandle.pNCSStateMutex->Lock();
                while (FALSE == m_hNCSPollThHandle.flushDone)
                {
                    result = m_hNCSPollThHandle.pNCSStateCondVar->TimedWait(
                        m_hNCSPollThHandle.pNCSStateMutex->GetNativeHandle(), 1000);
                    if (CamxResultETimeout == result)
                    {
                        CAMX_LOG_ERROR(CamxLogGroupNCS, "Flush timedout");
                        break;
                    }
                }
                m_hNCSPollThHandle.pNCSStateMutex->Unlock();

            }
            else
            {
                CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to flush, enqueue flush failed");
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupNCS, "Out of memory!!");
            result = CamxResultENoMemory;
        }

    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::EnqueueJob
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::EnqueueJob(
    NCSJob* pJob)
{
    CamxResult result = CamxResultSuccess;

    if (InvalidJobHandle != m_hNCSPollThHandle.hJobHandle)
    {
        CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Pushing Job to NCS job queue");

        m_hNCSPollThHandle.pNCSQMutex->Lock();

        // Enqueue if running.
        if (TRUE == m_hNCSPollThHandle.isRunning)
        {
            LDLLNode* pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));

            if (NULL != pNode)
            {
                pNode->pData = pJob;

                // Push job to NCS job queue.
                m_hNCSPollThHandle.NCSJobQueue.InsertToTail(pNode);
                m_hNCSPollThHandle.pNCSQCondVar->Signal();
            }
            else
            {
                result = CamxResultENoMemory;
            }
        }
        else
        {
            result = CamxResultEInvalidState;
            CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Failed, thread in invalid state, stopped");
        }
        m_hNCSPollThHandle.pNCSQMutex->Unlock();
    }
    else
    {
        CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Invalid Job handle");
        result = CamxResultEFailed;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::~NCSService
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
NCSService::~NCSService()
{
    NCSIntfQSEE* pQSEEIntfObject = NULL;

    for (UINT i = 0; i < MaxSensorInterfaceObjects; i++)
    {
        if (i == QSEE)
        {
            pQSEEIntfObject = static_cast<NCSIntfQSEE*>(m_hNCSServiceContext.pNCSIntfObject[i]);
            if (NULL != pQSEEIntfObject)
            {
                CAMX_LOG_INFO(CamxLogGroupNCS, "Destroying QSEE interface object");
                CAMX_DELETE pQSEEIntfObject;
                m_hNCSServiceContext.pNCSIntfObject[i] = NULL;
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::NCSServicePollThread
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID* NCSService::NCSServicePollThread(
    VOID* pPayload)
{
    NCSThreadContext* pNCSThreadContext = NULL;
    CamxResult        result            = CamxResultSuccess;
    BOOL              doExit            = FALSE;

    CAMX_LOG_INFO(CamxLogGroupNCS, "Starting poll thread");

    pNCSThreadContext = reinterpret_cast<NCSThreadData*>(pPayload)->pThreadContext;

    if (NULL != pNCSThreadContext)
    {
        pNCSThreadContext->flushDone = FALSE;
        pNCSThreadContext->isRunning = TRUE;

        while (FALSE == doExit)
        {
            CAMX_LOG_VERBOSE(CamxLogGroupNCS, "before wait");

            // Wait for data to be pushed to Q
            pNCSThreadContext->pNCSQMutex->Lock();

            result = pNCSThreadContext->pNCSQCondVar->TimedWait(
                pNCSThreadContext->pNCSQMutex->GetNativeHandle(), QSEECallbacksTimeout);

            // Process jobs only when somone has signalled on the queue
            if (CamxResultETimeout != result)
            {

                result = ProcessPendingJobs(pNCSThreadContext);
                if (CamxResultSuccess != result)
                {
                    CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to process jobs %s", CamxResultStrings[result]);
                }

                // Update the interface states
                result = UpdateIntfStates(pNCSThreadContext);
                if (CamxResultSuccess != result)
                {
                    CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to update interfaces states %s", CamxResultStrings[result]);
                    doExit = TRUE;
                }

                // if flush is is triggered then exit this thread loop.
                if (TRUE == pNCSThreadContext->flushDone)
                {
                    pNCSThreadContext->isRunning = FALSE;
                    doExit = TRUE;
                }
            }
            else
            {
                doExit = TRUE;
                CAMX_LOG_ERROR(CamxLogGroupNCS, "Connections timeout, no one's responding :( !");
            }

            pNCSThreadContext->pNCSQMutex->Unlock();
            if (TRUE == doExit)
            {
                break;
            }
        }
        CAMX_LOG_INFO(CamxLogGroupNCS, "Exiting poll thread");
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupNCS, "Invalid pointer");
    }

    return NULL;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::ProcessPendingJobs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult NCSService::ProcessPendingJobs(
    NCSThreadContext* pNCSThreadContext)
{
    NCSJob*           pJob              = NULL;
    NCSService*       pNCSServiceObject = NULL;
    CamxResult        result            = CamxResultEFailed;

    CAMX_ASSERT_MESSAGE(NULL != pNCSThreadContext, "Invalid thread context passed!!");

    pNCSServiceObject = static_cast<NCSService*>(pNCSThreadContext->pServiceObject);

    CAMX_LOG_VERBOSE(CamxLogGroupNCS, "JobQ signalled, Pending Jobs %d", pNCSThreadContext->NCSJobQueue.NumNodes());

    if (NULL != pNCSServiceObject)
    {
        pNCSThreadContext->pNCSStateMutex->Lock();
        LDLLNode* pNode = pNCSThreadContext->NCSJobQueue.RemoveFromHead();
        pNCSThreadContext->pNCSStateMutex->Unlock();

        // Process all pending jobs
        while (NULL != pNode)
        {
            // process a NCS Job
            pJob = static_cast<NCSJob*>(pNode->pData);
            CAMX_FREE(pNode);

            pNode = NULL;

            if (NULL != pJob)
            {
                INCSIntfBase* pNCSIntfObject = NULL;

                switch (pJob->jobType)
                {
                    case NCSFlushCmdType:
                        CAMX_LOG_INFO(CamxLogGroupNCS, "Flushing poll thread");
                        CAMX_LOG_VERBOSE(CamxLogGroupNCS, "Pending Jobs %d", pNCSThreadContext->NCSJobQueue.NumNodes());
                        pNCSThreadContext->pNCSStateMutex->Lock();

                        pNCSThreadContext->flushDone = TRUE;
                        result                       = CamxResultSuccess;

                        pNCSThreadContext->pNCSStateCondVar->Signal();
                        pNCSThreadContext->pNCSStateMutex->Unlock();
                        break;
                    case NCSRequestProcType:
                        pNCSIntfObject = pNCSServiceObject->m_hNCSServiceContext.pNCSIntfObject[QSEE];
                        result = pNCSIntfObject->ProcessJob(pJob->pPayload);
                        break;
                    default:
                        CAMX_LOG_ERROR(CamxLogGroupNCS, "Unhandle job type");
                        result = CamxResultENotImplemented;
                        break;
                }

                if (CamxResultSuccess != result)
                {
                    CAMX_LOG_ERROR(CamxLogGroupNCS, "Failure in processing the job");
                }

                CAMX_FREE(pJob);
                pJob = NULL;

                CAMX_LOG_VERBOSE(CamxLogGroupNCS, "After processing Pending Jobs %d",
                                 pNCSThreadContext->NCSJobQueue.NumNodes());
            }

            pNCSThreadContext->pNCSStateMutex->Lock();
            pNode = pNCSThreadContext->NCSJobQueue.RemoveFromHead();
            pNCSThreadContext->pNCSStateMutex->Unlock();
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupNCS, "Unable to process pending jobs, invalid pointer to the service object");
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NCSService::UpdateIntfStates
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult  NCSService::UpdateIntfStates(
    NCSThreadContext* pNCSThreadContext)
{
    NCSService*   pServiceObject = NULL;
    INCSIntfBase* pNCSIntfObj    = NULL;
    NCSIntfState  intfState      = NCSIntfStopped;
    INT           activeIntfs    = 0;
    CamxResult    result         = CamxResultEFailed;

    CAMX_ASSERT(NULL != pNCSThreadContext);

    pServiceObject = static_cast<NCSService*>(pNCSThreadContext->pServiceObject);

    CAMX_ASSERT(NULL != pServiceObject);

    for (UINT i = 0; i < MaxSensorInterfaceObjects; i++)
    {
        pNCSIntfObj = pServiceObject->m_hNCSServiceContext.pNCSIntfObject[i];

        if (NULL != pNCSIntfObj)
        {
            intfState = pNCSIntfObj->UpdateIntfState(NULL);
            if (NCSIntfRunning == intfState)
            {
                activeIntfs++;
            }
        }
    }

    if (activeIntfs > 0)
    {
        result = CamxResultSuccess;
    }
    else
    {
        result = CamxResultETimeout;
    }

    return result;
}

CAMX_NAMESPACE_END
